package cn.mulanbay.gateway.filter;

import cn.mulanbay.api.system.bean.RemoteOperationLog;
import cn.mulanbay.api.system.service.RemoteLogService;
import cn.mulanbay.business.handler.ThreadPoolHandler;
import cn.mulanbay.common.config.CacheKey;
import cn.mulanbay.common.util.DateUtil;
import cn.mulanbay.common.util.JsonUtil;
import cn.mulanbay.common.util.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.Ordered;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.time.LocalDateTime;

/**
 * 日志记录
 *
 * @author fenghong
 * @create 2022-01-16 10:00
 */
@RefreshScope
@Component
public class ApiLogFilter implements GlobalFilter, Ordered {

    private static final Logger logger = LoggerFactory.getLogger(ApiLogFilter.class);

    /**
     * 是否记录操作日志
     */
    @Value("${system.operationLog.enable:false}")
    boolean enableOperationLog;

    /**
     * 是否记录get请求的日志记录
     */
    @Value("${system.operationLog.logGet:false}")
    boolean logGet;

    /**
     * 需要添加lazy，否则gateway无法正常启动
     * Spring Cloud gateway无法直接使用OpenFeign
     */
    @Lazy
    @Autowired
    RemoteLogService remoteLogService;

    @Autowired
    ThreadPoolHandler threadPoolHandler;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        if(!enableOperationLog){
            return chain.filter(exchange);
        }
        HttpMethod method = exchange.getRequest().getMethod();
        if(method==HttpMethod.GET&&!logGet){
            return chain.filter(exchange);
        }
        // 获取request body
        GatewayContext gc = exchange.getAttribute(GatewayContext.CACHE_GATEWAY_CONTEXT);
        gc.setStartTime(System.currentTimeMillis());
        return chain.filter(exchange).then( Mono.fromRunnable(() -> {
            int statusCode = exchange.getResponse().getStatusCode() != null
                    ? exchange.getResponse().getStatusCode().value() : 500;
            gc.setStatusCode(statusCode);
            this.doLog(gc);
        }));
    }

    /**
     * 记录日志
     * @param gc
     */
    private void doLog(GatewayContext gc){
        try {
            LocalDateTime endTime = LocalDateTime.now();
            threadPoolHandler.pushThread(() -> {
                String uid = gc.getHeaders().getFirst(CacheKey.DETAILS_USER_ID);
                Long userId = null;
                if(StringUtil.isNotEmpty(uid)){
                    userId = Long.valueOf(uid);
                }
                RemoteOperationLog log = new RemoteOperationLog();
                log.setUrlAddress(gc.getPath());
                log.setMethod(gc.getMethod().name());
                //userId由网关设置
                log.setUserId(userId);
                log.setOccurStartTime(DateUtil.getLocalDateTime(gc.getStartTime()));
                log.setOccurEndTime(endTime);
                if(gc.getMethod()== HttpMethod.GET){
                    log.setParas(JsonUtil.beanToJson(gc.getFormData().toSingleValueMap()));
                }else{
                    log.setParas(gc.getCacheBody());
                }
                log.setIpAddress(gc.getIpAddress());
                log.setStatusCode(gc.getStatusCode());
                logger.debug("请求参数:"+log.getParas());
                remoteLogService.addOperationLog(log);
            });
        } catch (Exception e) {
            logger.error("记录日志异常",e);
        }

    }

    @Override
    public int getOrder() {
        return -100;
    }
}
